home *** CD-ROM | disk | FTP | other *** search
- Subject: v17i097: E, friendlier front-end to vi, Part03/03
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: speedboat jones <tcjones@watdragon.waterloo.edu>
- Posting-number: Volume 17, Issue 97
- Archive-name: e2/part03
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 3 (of 3)."
- # Contents: do_vi.c e.1 e.c read_hist.c
- # Wrapped by tcjones@watdragon on Thu Feb 9 10:01:03 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'do_vi.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'do_vi.c'\"
- else
- echo shar: Extracting \"'do_vi.c'\" \(4970 characters\)
- sed "s/^X//" >'do_vi.c' <<'END_OF_FILE'
- X#include "e.h"
- X
- X/*
- X * do_vi()
- X *
- X * Split the arguments (if any) in 'thing' up to be passed to execvp,
- X * and exec vi on them. The arguments in 'thing' are space separated.
- X * Just walk down the 'thing' array, zero the spaces and set pointers
- X * to the arguments.
- X *
- X */
- X
- void
- do_vi(thing)
- char *thing;
- X{
- X char *args[MAX_ARGS];
- X register int i = 1;
- X int go_home = 0;
- X
- X args[0] = "vi";
- X skip_white(thing);
- X
- X while (*thing){
- X register char *tmp = thing;
- X skip_to_white(tmp);
- X if (*tmp) *tmp++ = '\0';
- X skip_white(tmp);
- X
- X if (i > 1 || (*thing != '-' && *thing != '+')){
- X if (safety_first(thing)){
- X /*
- X * Have to go home for this one.
- X * Grab some space to put the new filename into.
- X * The filename is to be cwd/thing.
- X *
- X */
- X char *space = sbrk(MAXPATHLEN + 1);
- X go_home = 1;
- X if (space == (char *)-1){
- X e_error("Could not sbrk.");
- X }
- X sprintf(space, "%s/%s", cwd, thing);
- X thing = space;
- X }
- X }
- X args[i++] = thing;
- X thing = tmp;
- X }
- X
- X args[i] = NULL;
- X
- X if (go_home && chdir(home) == -1){
- X e_error("Could not chdir to '%s'.", home);
- X }
- X
- X if (execvp(VI, args) == -1){
- X e_error("Could not execvp '%s'", VI);
- X }
- X}
- X
- X
- int
- safety_first(s)
- char *s;
- X{
- X register char *slash;
- X struct stat sbuf;
- X char away_dir[MAXPATHLEN];
- X int away;
- X int own;
- X
- X /*
- X * If they are not concerned with inheritance, just return.
- X *
- X */
- X if (!safe_inherit && !inherit){
- X return 0;
- X }
- X
- X /*
- X * See if there is a .exrc file in the directory in which the file we
- X * are going to be editing lives.
- X */
- X slash = rindex(s, '/');
- X
- X if (slash){
- X /*
- X * The file we are editing lies (probably) in a directory that is
- X * not the one we are in. Check it by inode numbers though.
- X *
- X */
- X char tmp[MAXPATHLEN];
- X ino_t here_ino;
- X
- X *slash = '\0';
- X ok_sprintf(away_dir, "%s", s);
- X *slash = '/';
- X ok_sprintf(tmp, "%s/.exrc", away_dir);
- X
- X if (stat(tmp, &sbuf) == -1){
- X /*
- X * There is no .exrc file.
- X *
- X */
- X return 0;
- X }
- X
- X /*
- X * There is a .exrc file.
- X *
- X */
- X if (uid == sbuf.st_uid){
- X /*
- X * And we own it.
- X *
- X */
- X away = 1;
- X own = 1;
- X }
- X else{
- X /*
- X * We don't own the .exrc file.
- X *
- X */
- X own = 0;
- X }
- X
- X /*
- X * Decide whether or not the file we are going to edit is in
- X * this directory. We may have been deceived by the presence of the
- X * '/' since the filename could be ../this_dir etc etc.
- X *
- X */
- X
- X if (stat(cwd, &sbuf) == -1){
- X e_error("Cannot stat '%s'.", cwd);
- X }
- X here_ino = sbuf.st_ino;
- X
- X if (stat(away_dir, &sbuf) == -1){
- X e_error("Cannot stat '%s'.", away_dir);
- X }
- X
- X if (sbuf.st_ino == here_ino){
- X away = 0;
- X }
- X else{
- X away = 1;
- X }
- X }
- X else{
- X /*
- X * The file is in this directory.
- X *
- X */
- X
- X /*
- X * We know we are away, there was no '/' in the filename.
- X * The possibility of the filename being a link is excluded I
- X * think, because earlier on we checked for regular files.
- X * I'll check this again. In any case no harm could come as
- X * at worst we would attempt to vi a directory.
- X *
- X */
- X away = 0;
- X
- X if (stat(".exrc", &sbuf) == -1){
- X /*
- X * No .exrc file.
- X *
- X */
- X return 0;
- X }
- X
- X if (uid == sbuf.st_uid){
- X own = 1;
- X }
- X else{
- X own = 0;
- X }
- X }
- X
- X /*
- X * We have now set up 'away' and 'own'.
- X *
- X * away = 1 => The file we are editing is not in our current directory.
- X * away = 0 => The file we are editing is in our current directory.
- X *
- X * own = 1 => We own the .exrc file.
- X * own = 0 => We do not own the .exrc file.
- X *
- X *
- X */
- X
- X /*
- X * It's in this directory and we own it. So just return and pretend
- X * to be a normal vi :-)
- X *
- X */
- X if (!away && own){
- X return 0;
- X }
- X
- X /*
- X * It's in this directory and we don't own it and we don't want to inherit
- X * it.
- X *
- X * Return 1 to indicate that the filename that needs to be edited
- X * should now be preceeded by 'cwd/'. And that we need to chdir to home
- X * before we exec vi.
- X *
- X */
- X if (!away && !own && safe_inherit){
- X return 1;
- X }
- X
- X /*
- X * The other option is that it's in this directory and we don't own
- X * it and either 1) inherit is set or 2) inherit is not set AND neither
- X * is safe_inherit. In either case we are going to inherit the thing.
- X *
- X */
- X
- X /*
- X * Now to the cases where the file we are going to edit is not in
- X * this directory.
- X *
- X */
- X
- X /*
- X * It's not in this directory and we own it and we want to inherit.
- X * So chdir over there before returning.
- X *
- X */
- X if (away && own && inherit){
- X if (chdir(away_dir) == -1){
- X e_error("Could not chdir to '%s'.", away_dir);
- X }
- X return 0;
- X }
- X
- X /*
- X * It's not in this directory and we don't own it and we want to inherit
- X * even if it's not safe. So chdir over there before returning.
- X *
- X */
- X if (away && !own && inherit && !safe_inherit){
- X if (chdir(away_dir) == -1){
- X e_error("Could not chdir to '%s'.", away_dir);
- X }
- X return 0;
- X }
- X
- X /*
- X * And I think that's about it. Time will tell.
- X *
- X */
- X
- X return 0;
- X}
- END_OF_FILE
- if test 4970 -ne `wc -c <'do_vi.c'`; then
- echo shar: \"'do_vi.c'\" unpacked with wrong size!
- fi
- # end of 'do_vi.c'
- fi
- if test -f 'e.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'e.1'\"
- else
- echo shar: Extracting \"'e.1'\" \(9576 characters\)
- sed "s/^X//" >'e.1' <<'END_OF_FILE'
- X.TH E P "November 16, 1988"
- X.SH NAME
- e \- command line preprocessor for the vi(1) editor.
- X.SH SYNOPSIS
- X.B e
- X[
- X.B option
- X] [
- X.B file
- X] ...
- X.SH DESCRIPTION
- X.I e
- is an interface to
- X.IR vi (1)
- that maintains a history of the most recently
- X.IR e 'ed
- files for each directory.
- Using the history, it is both fast and simple to re-edit
- previously
- X.IR e 'ed
- files.
- X.PP
- In addition,
- X.I e
- does spelling corrections on its arguments,
- fast lookup and editing of files in other directories, and allows for
- the inheritance of .exrc
- files in other directories. It also closes the modeline security hole,
- making it possible to ensure that no .exrc file
- that you don't own is ever seen by
- X.IR vi .
- X.PP
- X.SH INVOCATION
- The invocation syntax is (almost) a superset of that of
- X.IR vi .
- A list of the interesting command line variations is given below.
- X[x] indicates that "x" is optional. "cmd" means an
- X.IR ex (1)
- command.
- X.TP 18
- X.B e
- Invokes
- X.I vi
- on the last file that was
- X.IR e 'ed
- in this directory.
- X.TP 18
- X.B e \-
- Prints the history for this directory and allows fast selection
- of a previous file - or a new one.
- X.TP 18
- X.B e .
- Prints the history for this directory without asking for input.
- X.TP 18
- X.B e \-pat
- X.IR vi 's
- the last file that was
- X.IR e 'ed
- with the string "pat" on
- the command line.
- X.TP 18
- X.B e +[cmd]
- X.IR vi 's
- the last file that was
- X.IR e 'ed
- in this directory, but executes
- command "cmd" on entering
- X.IR vi .
- X.TP 18
- X.B e [+[cmd]] file
- X.IR vi 's
- the file and adds it to the history list. Minor spelling
- corrections are suggested if "file" does not exist but is close
- X(in spelling) to some file that does.
- X.TP 18
- X.B e [+[cmd]] files
- X.IR vi 's
- the files and adds them as a single entry to the history.
- X.PP
- The
- X.IR vi (1)
- options \-r, \-v, \-x, \-w and \-R are all passed as is to
- X.I vi
- and so behave as would be expected.
- X.SH EXAMPLE
- Assume here that you are in the directory /tmp/mydir and that it
- contains (only) the files "death", "main.c", "pete.c", "bigmac"
- and "fries"; and that your
- X.I e
- history file contains
- X.PP
- X.in 0.5i
- X.B /tmp/mydir
- X.in 1.0i
- X.B death
- X.br
- X.B +/main.c pete.c
- X.br
- X.B bigmac
- X.br
- X.B fries
- X.br
- X.PP
- X"\fBe .\fR" will show you the history...
- X.PP
- X.in 1.0i
- X.B [3]: death
- X.br
- X.B [2]: +/main pete.c
- X.br
- X.B [1]: bigmac
- X.br
- X.B [0]: fries
- X.br
- X.PP
- X"\fBe\fR" by itself will get you immediately back into "fries".
- X.PP
- X"\fBe \-\fR" will present the same as shown for "\fBe .\fR",
- but will ask for a number or another filename.
- Carriage return is equivalent to zero (i.e. the last filename),
- backspace or interrupt will quit.
- X.PP
- X"\fBe -2\fR" will get you immediately into "pete.c", searching for
- X"main" on entering
- X.IR vi .
- X.PP
- X"\fBe \-ath\fR" searches for the pattern "ath", finds it in "death",
- and that's what you get.
- X.PP
- X"\fBe +10\fR"
- will get you into "fries" on line 10 (assuming it has 10 lines).
- X.SH "THE HISTORY"
- A single history file is kept. Its default location is $HOME/.e but this
- can be changed with the VIHIST environment variable.
- The history is rearranged with each use to place the last
- X.IR e 'ed
- file at the end of the list. Duplicate entries are removed.
- The number of history items kept for each directory is 8. Seeing as the
- list is ordered by use, this number is ample.
- X.PP
- The history file consists of entries composed of a directory name followed by
- lines of file names (oldest to newest). Each filename is preceded by a
- single TAB character. The directory names are all absolute pathnames.
- X.SH "FILENAME CORRECTION"
- If you make a simple spelling mistake when typing a file name,
- X.I e
- will detect it, ask whether it was really what you meant, and offer
- suggestions.
- XErrors that are detected are: wrong character, omitted character,
- interchanged characters and extra character.
- X.PP
- In the above example,
- X"\fBe bigamc\fR"
- will prompt you with
- X.br
- X.in 1.0i
- X"correct to bigmac [y]?"
- X.PP
- Answering "n" will not do the correction, "Q" or "q" will quit.
- If there is more than one possible correction,
- you will be prompted for each in
- turn. A response of "N" means that you really want what you typed, and no
- further corrections will be offered.
- Any other response (e.g. a RETURN) will do the correction for you.
- X.SH "CROSS-DIRECTORY EDITING"
- The environment variable VIPATH can be used to enable fast lookup and
- editing of files
- in different directories. It should contain a list of directories that you want
- searched when
- X.I e
- cannot find the file you request in the current
- directory. Here is an example:
- X.PP
- Suppose you are in the directory /bin with VIPATH set to /usr/include/sys
- X.PP
- X"\fBe inode.h\fR"
- will prompt you with
- X.br
- X.in 1.0i
- X"/usr/include/sys/inode.h [y]?"
- X.PP
- since /bin/inode.h does not exist, but /usr/include/sys/inode.h does.
- You can say "n" or "q" to reject or quit.
- X"N" will reject the current suggestion and
- searching for further ones will be stopped.
- Any other response (e.g. a RETURN) is taken as a yes.
- X.PP
- It is handy to have $HOME in your VIPATH, this gives you easy access
- from anywhere to commonly used files.
- X.PP
- If you accept a suggestion, then the file is put into the history.
- Spelling corrections are not suggested across directories.
- There is (of course) no need to put "." in your VIPATH. Doing so will just slow
- things down and cannot possibly be of help.
- This should be clear, "." is always searched first for the given filename.
- Putting it into your VIPATH will have it searched twice. The directory names
- in VIPATH may be separated by white space (including newlines) and colons.
- X.SH ".exrc INHERITANCE"
- If you set the environment variable "VIINHERIT",
- X.I e
- will look for
- a .exrc file in the directory where the (first) file you are about to edit
- resides. If it finds
- one, it arranges to read it as though it were in the directory from which you
- issued the
- X.I e
- command. This is very useful as many people
- have specialised .exrc files in their directory trees.
- X.PP
- XFor instance, in a directory of C source
- you might like to set autoindent and showmatch, whereas in a directory that
- contained correspondence, you might want neither of these, but wrapmargin and
- ignorecase instead. Inherited .exrc files allow you to
- X.I e
- files in other
- directories and get the results intended by the .exrc files in them.
- X.PP
- There is a drawback however.
- X.I vi
- has an option called "modeline"
- which makes it possible for a malicious user to leave a trojan-horse type file
- in a directory with a specially prepared .exrc file that turns on "modeline".
- As a result, if you cd to that directory and
- X.I vi
- the wrong file, then the modeline feature allows the other user to execute
- commands as you. Not nice.
- X.PP
- If you set "VISAFEINHERIT",
- X.I e
- will make sure that you never get caught by
- this one. In short, it notices when this could happen and changes directory
- to avoid the .exrc. There is no need to have "VIINHERIT" set if all you want to
- do is avoid the security problem. But setting them both gives you the best of
- both worlds. (See the NOTES for the drawback...)
- X.SH NOTES
- When using "e -", the terminal is put into cbreak mode. If the first
- character typed is a digit (in the acceptable range of history items)
- then you will get that history item without further ado. Thus if you
- have a file called 4play and you try to type "4play" from within an "e -",
- then you'll probably end up in the wrong place.
- This is to say you'll get the file that was the 4th last in the history.
- X.PP
- The history length must be less than or equal to 9 (the code sets
- it to 8 at present).
- The problem with having more is that with "e -" you go into cbreak and the
- first digit entered (say
- X.I n
- X) is taken to mean
- X"I want the
- X.IR n th
- last file". This saves the need for hitting return, but also means that
- two digit numbers can't be done.
- X.PP
- When "VISAFEINHERIT" is set and your command would have resulted in
- X.I vi
- going through a foreign .exrc,
- X.I e
- will change the name
- of the file you want to its full path name, and change directory underneath
- you to your home directory. For example, if user joe says "e file" in /tmp and
- user mary owns /tmp/.exrc, then the result will be as though joe had typed "e
- X/tmp/file" from his home directory. Of course when he exits
- X.I vi
- he will still
- be in /tmp. Perhaps this could be considered a bug. If you don't like it,
- you can live with the modeline problem.
- X.PP
- The same problem with the directory changing underneath you happens when
- X.I e
- inherits a .exrc for you (via "VIINHERIT") \- you get changed to that
- directory while you are in vi.
- X.SH FILES
- X$HOME/.e \- the default e history file.
- X.SH "ENVIRONMENT VARIABLES"
- VIHIST \- The location used by e for the history.
- X.br
- VIPATH \- Search directories.
- X.br
- VIINHERIT \- If set,
- X.I e
- tries to inherit .exrc files.
- X.br
- VISAFEINHERIT \- Ensures you don't inadvertently go through someone
- else's .exrc file.
- X.SH BUGS
- The first character on a select line cannot be backspaced over.
- X.br
- The
- X.I vi
- option "\-" is not available. I should have chosen another letter.
- X.SH "SEE ALSO"
- ex(1), edit(1).
- X.SH AUTHOR
- Terry Jones
- X.br
- Department of Computer Science
- X.br
- University of Waterloo
- X
- X.\"
- X.\" Man page for e. Version 1.3
- X.\"
- X.\" ------------------------------------------------------------------------
- X.\" Terry Jones, Department Of Computer Science, University Of Waterloo
- X.\" Waterloo Ontario Canada N2L 3G1
- X.\"
- X.\" {ihnp4,allegra,decvax,utzoo,utcsri,clyde}!watmath!watdragon!tcjones
- X.\" tcjones@dragon.waterloo.{cdn,edu} tcjones@WATER.bitnet
- X.\" tcjones%watdragon@waterloo.csnet
- X.\" -------------------------------------------------------------------------
- X.\"
- END_OF_FILE
- if test 9576 -ne `wc -c <'e.1'`; then
- echo shar: \"'e.1'\" unpacked with wrong size!
- fi
- chmod +x 'e.1'
- # end of 'e.1'
- fi
- if test -f 'e.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'e.c'\"
- else
- echo shar: Extracting \"'e.c'\" \(5750 characters\)
- sed "s/^X//" >'e.c' <<'END_OF_FILE'
- X#include "e.h"
- X
- void
- e(c, v)
- int c;
- char **v;
- X{
- X /*
- X * Process the command line. This gets a little messy as there are so
- X * many ways e can be invoked. They are listed below and there is an
- X * example provided in each of the switch cases to illustrate the
- X * particular one we are trying to handle.
- X *
- X * The idea in most cases is to get the arguments that will be passed
- X * to vi into a character array (arg), and pass it to do_vi(). do_vi()
- X * splits up the arguments and execs vi. Occasionally it is simpler and
- X * do_vi() can be called more directly.
- X *
- X *
- X * Command Line Options.
- X * =====================
- X *
- X * No arguments.
- X *
- X * (1) "e"
- X *
- X * One argument.
- X *
- X * (2) "e -"
- X * (3) "e -#" # is the number of some history item.
- X * (4) "e -r"
- X * (5) "e -pat" pat is a search pattern.
- X * (6) "e +100"
- X * (7) "e ."
- X * (8) "e <filename > "
- X *
- X * Multiple arguments.
- X *
- X * (9) "e fred harry joe" Also handles "e -t tag", "e -r file" etc.
- X *
- X */
- X
- X
- X switch (c){
- X case 1: {
- X
- X /*
- X * Command line option (1).
- X * Example: "e"
- X *
- X * Just go and vi the last file that was e'ed.
- X *
- X */
- X
- X check_hist();
- X abandon();
- X do_vi(hist[hist_count - 1]);
- X break;
- X }
- X
- X case 2:{
- X switch ((*++v)[0]){
- X
- X case '-':{
- X
- X if ((c = (*v)[1]) == '\0'){
- X
- X /*
- X * Command line option (2).
- X * Example: "e -"
- X *
- X * This is a select from history, ask what they want.
- X *
- X */
- X
- X check_hist();
- X ask_hist();
- X do_vi(arg);
- X }
- X else if (isdigit(c)){
- X
- X /*
- X * Command line option (3).
- X * Example: "e -3"
- X *
- X * Get the nth last file from the history and vi it.
- X *
- X */
- X
- X check_hist();
- X nth_hist(c-'0');
- X do_vi(arg);
- X }
- X else if (c == 'r' && (*v)[2] == '\0'){
- X
- X /*
- X * Command line option (4).
- X * Example: "e -r"
- X *
- X * A recover, just pass it to vi and don't interfere.
- X *
- X */
- X
- X do_vi(*v);
- X }
- X else{
- X
- X /*
- X * Command line option (5).
- X * Example: "e -pat"
- X *
- X * This is a pattern - try to match it.
- X *
- X */
- X
- X check_hist();
- X find_match(++*v);
- X do_vi(arg);
- X }
- X break;
- X }
- X
- X case '+':{
- X
- X /*
- X * Command line option (6).
- X * Example: "e +100"
- X *
- X * A command, put it before the last file name.
- X *
- X */
- X
- X check_hist();
- X insert_cmd(*v);
- X do_vi(arg);
- X break;
- X }
- X
- X case '.':{
- X
- X /*
- X * Command line option (7).
- X * Example: "e ."
- X * Example: "e .login" (falls through to option (8)).
- X *
- X * Just give a history list if there is only a dot.
- X * Otherwise fall through as it must be a filename.
- X *
- X */
- X
- X if ((*v)[1] == '\0'){
- X register i;
- X
- X check_hist();
- X for (i = 0; i < hist_count; i++){
- X ok_fprintf(stderr, "\t[%d]: %s\n",
- X hist_count - i - 1, hist[i]);
- X }
- X abandon();
- X }
- X /*
- X * The switch falls through in the case where there is a
- X * filename that starts with a period.
- X *
- X */
- X
- X }
- X /* FALLTHROUGH */
- X
- X default :{
- X
- X /*
- X * Command line option (8).
- X * Example: "e fred"
- X * Example: "e .login" (fell through from option (8)).
- X *
- X * Looks like it's just a plain old file name. vi it!
- X *
- X */
- X
- X normal(*v);
- X do_vi(arg);
- X break;
- X }
- X }
- X break;
- X }
- X
- X default:{
- X
- X /*
- X * Command line option (9).
- X * Example: "e fred harry joe"
- X *
- X * A bunch of arguments, fix the history & vi them all as normal.
- X *
- X */
- X
- X multiple(c, v, ARG_CHARS);
- X do_vi(arg);
- X break;
- X }
- X }
- X}
- END_OF_FILE
- if test 5750 -ne `wc -c <'e.c'`; then
- echo shar: \"'e.c'\" unpacked with wrong size!
- fi
- # end of 'e.c'
- fi
- if test -f 'read_hist.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'read_hist.c'\"
- else
- echo shar: Extracting \"'read_hist.c'\" \(6117 characters\)
- sed "s/^X//" >'read_hist.c' <<'END_OF_FILE'
- X#include "e.h"
- X
- X/*
- X * read_hist()
- X *
- X * Do some initialization type things such as finding out if the user has a
- X * uid, password entry, home directory etc. Then find out where the history
- X * is kept and check to see if it's there. If it's not just indicate this by
- X * returning -1 and let other functions deal with this problem as they see
- X * fit.
- X *
- X * If the history exists then read it. The format of the history file is
- X *
- X
- X/absolute/path/name/for/some/directory
- X\tfilename_1
- X\tfilename_2
- X\tfilename_3
- X\tfilename_4
- X/absolute/path/of/some/other/directory
- X\tsome_filename_or_other
- X\tanother_filename
- X
- X *
- X * Where \t is of course a single TAB.
- X * The files for a directory are kept in least recently used order. So in
- X * the above example, 'filename_1' was used before 'filename_2' and so on.
- X * There may be a maximum of HIST_LINES file names associated with each
- X * directory.
- X *
- X * If the history is used and needs to be updated, then we will have to create
- X * a new file that looks pretty much like the current one. Unfortunately we
- X * will have to read and write the whole of the old file.
- X *
- X * Seeing as we are going to have to write the new history file, it doesn't
- X * make much sense to try and find the relevant directory in a clever manner
- X * (e.g. by keeping the history sorted by directory). The point is that
- X * we HAVE to read and write the whole file once so it doesn't really matter
- X * where we encounter the directory we want (if at all).
- X *
- X *
- X * We return the number of history items found after setting the pointers in
- X * hist[] to point to them. hist[0] points to the oldest filename, hist[1]
- X * to the next oldest etc etc... hist[hist_count - 1] to the most recently
- X * used.
- X *
- X */
- X
- int
- read_hist()
- X{
- X static char line[MAXPATHLEN]; /* Static, as saved_line may point at it. */
- X int h_index = 0; /* # of history items found so far. */
- X register int cwd_len; /* # of chars in the current dir name. */
- X struct stat sbuf;
- X
- X cwd_len = strlen(cwd);
- X
- X if (stat(ehist, &sbuf) == -1){
- X return -1;
- X }
- X
- X emode = (int)sbuf.st_mode;
- X
- X hist_fp = fopen(ehist, "r");
- X if (!hist_fp){
- X e_error("Could not open history '%s'.", ehist);
- X }
- X
- X /*
- X * Open a new history file that will renamed to the old one once
- X * we update. (If we update.)
- X *
- X */
- X
- X get_temp();
- X
- X /*
- X * Make sure that the first line of the history starts with a '/'
- X * This way we know we are not dealing with an old-style (pre version 1.3)
- X * history file. The error message here is unsatisfactory - it should make
- X * a better attempt to find out what's wrong and point them to the
- X * script for converting to the new format etc etc. Fortunately I'm the
- X * only person in the world who uses e and so it's not a problem.
- X *
- X */
- X
- X if (!fgets(line, MAXPATHLEN, hist_fp)){
- X e_error("Could not read first line of '%s'.\n", ehist);
- X }
- X
- X if (line[0] != '/'){
- X e_error("The history (%s) is munged. It is not in version %s format.",
- X ehist, VERSION);
- X }
- X
- X ok_fprintf(tmp_fp, "%s", line);
- X
- X /*
- X * Get lines and write them to the new history until you see one that
- X * matches the directory we are in.
- X *
- X */
- X while (fgets(line, MAXPATHLEN, hist_fp)){
- X
- X register char *tmp = line;
- X int room_left = HIST_LINES * MAXPATHLEN;
- X char *room;
- X
- X /*
- X * If it's not a path starting with a '/' then continue.
- X * We have a filename. Keep going until the next directory entry.
- X *
- X */
- X if (line[0] != '/'){
- X ok_fprintf(tmp_fp, "%s", line);
- X continue;
- X }
- X
- X zap_nl(tmp);
- X
- X /*
- X * Test to see if this is the directory we want. tmp - line is the
- X * length of the name of the found directory. Do a length test first
- X * up to avoid a strcmp if possible.
- X *
- X */
- X if (tmp - line != cwd_len || strcmp(line, cwd)){
- X ok_fprintf(tmp_fp, "%s\n", line);
- X continue;
- X }
- X
- X /*
- X * So we have found the directory we were looking for. Allocate a
- X * hunk of space to read all the filenames.
- X */
- X room = sbrk(room_left);
- X if (room == (char *)-1){
- X e_error("Could not sbrk().");
- X }
- X
- X /*
- X * Read the filenames. If we reach a line that starts with a '/'
- X * then we are onto the next directory in the history and we save
- X * a pointer to this line to emit it later.
- X *
- X */
- X while (fgets(room, room_left, hist_fp)){
- X char *cp = hist[h_index] = room + 1;
- X zap_nl(cp);
- X room_left -= (cp - room);
- X
- X /*
- X * In theory we should never run out of space, but in case we do
- X * we might as well try to grab some more rather than just dying.
- X *
- X */
- X if (room_left <= MAXPATHLEN){
- X room_left = HIST_LINES * MAXPATHLEN;
- X room = sbrk(room_left);
- X if (room == (char *)-1){
- X e_error("Could not sbrk().");
- X }
- X }
- X
- X if (*room == '/'){
- X saved_line = room; /* Read one too many! */
- X return h_index;
- X }
- X
- X room = cp + 1;
- X h_index++;
- X
- X /*
- X * Check to see if we have read HIST_LINES filenames. If we have,
- X * make sure that the next line is in fact a directory (by
- X * verifying that it starts with a '/'.
- X *
- X */
- X if (h_index == HIST_LINES){
- X if (fgets(line, MAXPATHLEN, hist_fp)){
- X if (line[0] != '/'){
- X e_error("History contains too many entries!");
- X }
- X else{
- X tmp = line;
- X zap_nl(tmp);
- X saved_line = line;
- X }
- X }
- X return HIST_LINES;
- X }
- X }
- X return h_index;
- X }
- X return h_index;
- X}
- END_OF_FILE
- if test 6117 -ne `wc -c <'read_hist.c'`; then
- echo shar: \"'read_hist.c'\" unpacked with wrong size!
- fi
- # end of 'read_hist.c'
- fi
- echo shar: End of archive 3 \(of 3\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-